home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume10 / b+tree_mjr / part05 < prev    next >
Encoding:
Text File  |  1990-01-19  |  45.2 KB  |  1,802 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i031: B+tree library, part05 of 5
  3. from: mjr@umiacs.UMD.EDU (Marcus J. Ranum)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 31
  7. Submitted-by: mjr@umiacs.UMD.EDU (Marcus J. Ranum)
  8. Archive-name: b+tree_mjr/part05
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 5 (of 5)."
  17. # Contents:  b+tree/doc/btree.3 b+tree/utils/btest.c
  18. # Wrapped by mjr@atreus on Fri Jan 19 10:34:59 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'b+tree/doc/btree.3' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'b+tree/doc/btree.3'\"
  22. else
  23. echo shar: Extracting \"'b+tree/doc/btree.3'\" \(24047 characters\)
  24. sed "s/^X//" >'b+tree/doc/btree.3' <<'END_OF_FILE'
  25. X.\"
  26. X.\"         (C) Copyright, 1988, 1989 Marcus J. Ranum
  27. X.\"                    All rights reserved
  28. X.\"
  29. X.\"
  30. X.\"          This software, its documentation,  and  supporting
  31. X.\"          files  are  copyrighted  material  and may only be
  32. X.\"          distributed in accordance with the terms listed in
  33. X.\"          the COPYRIGHT document.
  34. X.\"
  35. X.\" $Header: /atreus/mjr/hacks/btree/doc/RCS/btree.3,v 1.4 89/10/23 15:37:43 mjr Rel $
  36. X.\"
  37. X.TH B\+TREE 3 "30 September 1989"
  38. X.SH NAME
  39. Xb+tree \- variable length b+tree index management package
  40. X.SH SYNOPSIS
  41. X.B #include <sys/types.h>
  42. X.br
  43. X.B #include <btree.h>
  44. X.sp
  45. X.LP
  46. X.B "BT_INDEX bt_open(path,flags,mode)"
  47. X.br
  48. X.B "char *path;"
  49. X.br
  50. X.B "int flags;"
  51. X.br
  52. X.B "int mode;"
  53. X.LP
  54. X.B #include <varargs.h>
  55. X.br
  56. X.B "BT_INDEX bt_optopen(va_alist)"
  57. X.LP
  58. X.B "int bt_delete(btree,key,len)"
  59. X.br
  60. X.B "BT_INDEX *btree;"
  61. X.br
  62. X.B "bt_chrp key;"
  63. X.br
  64. X.B "int len;"
  65. X.LP
  66. X.B "int bt_find(btree,key,len,rrn)"
  67. X.br
  68. X.B "BT_INDEX *btree;"
  69. X.br
  70. X.B "bt_chrp key;"
  71. X.br
  72. X.B "int len;"
  73. X.br
  74. X.B "off_t *rrn;"
  75. X.LP
  76. X.B "int bt_goto(btree,d)"
  77. X.br
  78. X.B "BT_INDEX *btree;"
  79. X.br
  80. X.B "int d; /* BT_EOF or BT_BOF */"
  81. X.LP
  82. X.B "int bt_insert(btree,key,len,rrn,dupflg)"
  83. X.br
  84. X.B "BT_INDEX *btree;"
  85. X.br
  86. X.B "bt_chrp key;"
  87. X.br
  88. X.B "int len;"
  89. X.br
  90. X.B "off_t rrn;"
  91. X.br
  92. X.B "int dupflg;"
  93. X.LP
  94. X.B "int bt_traverse(btree,d,kbuf,maxlen,retlen,retrrn)"
  95. X.br
  96. X.B "BT_INDEX *btree;"
  97. X.br
  98. X.B "int d; /* BT_EOF or BT_BOF */"
  99. X.br
  100. X.B "bt_chrp kbuf;"
  101. X.br
  102. X.B "int maxlen;"
  103. X.br
  104. X.B "int *retlen;"
  105. X.br
  106. X.B "off_t *retrrn;"
  107. X.LP
  108. X.B "void bt_perror(btree,s)"
  109. X.br
  110. X.B "BT_INDEX *btree;"
  111. X.br
  112. X.B "char *s;"
  113. X.LP
  114. X.B "int bt_rlabel(btree,buf,siz)"
  115. X.br
  116. X.B "BT_INDEX *btree;"
  117. X.br
  118. X.B "bt_chrp buf;"
  119. X.br
  120. X.B "int siz;"
  121. X.LP
  122. X.B "int bt_wlabel(btree,buf,siz)"
  123. X.br
  124. X.B "BT_INDEX *btree;"
  125. X.br
  126. X.B "bt_chrp buf;"
  127. X.br
  128. X.B "int siz;"
  129. X.LP
  130. X.B "int bt_sync(btree)"
  131. X.br
  132. X.B "BT_INDEX *btree;"
  133. X.LP
  134. X.B "int bt_close(btree)"
  135. X.br
  136. X.B "BT_INDEX *btree;"
  137. X.LP
  138. X.B "int bt_load(btree,key,len,rrn,flag)"
  139. X.br
  140. X.B "BT_INDEX *btree;"
  141. X.br
  142. X.B "bt_chrp key;"
  143. X.br
  144. X.B "int len;"
  145. X.br
  146. X.B "off_t rrn;"
  147. X.br
  148. X.B "int flag; /* either BT_BOF, BT_OK, or BT_EOF */"
  149. X.LP
  150. X.B "int bt_zap(btree)"
  151. X.br
  152. X.B "BT_INDEX *btree;"
  153. X.LP
  154. X.B "The following are macros:"
  155. X.LP
  156. X.B "(int) bt_fileno(btree)"
  157. X.br
  158. X.B "BT_INDEX *btree;"
  159. X.LP
  160. X.B "(int) bt_pagesiz(btree)"
  161. X.br
  162. X.B "BT_INDEX *btree;"
  163. X.LP
  164. X.B "(int) bt_dtype(btree)"
  165. X.br
  166. X.B "BT_INDEX *btree;"
  167. X.LP
  168. X.B "(*int)() bt_cmpfn(btree)"
  169. X.br
  170. X.B "BT_INDEX *btree;"
  171. X.LP
  172. X.B "(int) bt_errno(btree)"
  173. X.br
  174. X.B "BT_INDEX *btree;"
  175. X.LP
  176. X.B "(void) bt_clearerr(btree)"
  177. X.br
  178. X.B "BT_INDEX *btree;"
  179. X.LP
  180. X.B "(int) BT_MAXK(btree)"
  181. X.br
  182. X.B "BT_INDEX *btree;"
  183. X.LP
  184. X.B "(int) BT_LABSIZ(btree)"
  185. X.br
  186. X.B "BT_INDEX *btree;"
  187. X.SH DESCRIPTION
  188. X.LP
  189. XThe b+tree library implements a variable-length key variable page size b+tree.
  190. XA variety of options are supported, including user-settable cache modes,
  191. Xcache sizes, user defined data types, and several system defined data types.
  192. XSupport for variable length string keys with automatic prefixing is built
  193. Xin. The library does \fINOT\fR support any means of data storage for anything
  194. Xmore than keys - for that the user must have access to a record management
  195. Xlibrary (such as
  196. X.B "store(3)"
  197. Xor
  198. X.B "btdbm(3)"
  199. X\).
  200. X.LP
  201. XThe b+tree library stores all keys as variable length blocks of
  202. Xunsigned chars, and associates a \fIRemote Record Number (RRN)\fP
  203. Xwith each key. This is defined as the typedef
  204. X.B off_t
  205. Xand is typically used to store a disk address of a record someplace
  206. Xelse in secondary storage. There is no provision for storing more
  207. Xassociated data than the \fIRRN\fP in the index.
  208. XThe typedef
  209. X.B bt_chrp
  210. Xis provided to increase portability and should be used in preference to
  211. Xa char pointer, though they may really be the same type. 
  212. X.SH "INITIALIZING A B+TREE"
  213. X.LP
  214. XWhen a b+tree is opened, an attempt is made to read a block of information
  215. Xat the beginning of the file which contains parameters such as page size, etc.
  216. XIf no bytes are read, indicating the file is empty, this is
  217. Xtaken as an indication that the file should be initialized, and a new b+tree
  218. Xis created. To prevent confusion, a variety of checks are made, including
  219. Xverifying that a magic number is correct, and that any parameters provided
  220. Xmake sense. If the open succeeds, a pointer to a dynamically allocated
  221. Xb+tree index is returned. In the event of an error, a NULL pointer is
  222. Xreturned.
  223. X.LP
  224. XIf an existing b+tree is re-opened, the information in the header block
  225. Xmay override any options from the user, if appropriate. Thus, if a b+tree
  226. Xhas already been created with one page size, attempts to use a different
  227. Xpage size are politely ignored.
  228. X.SH "OPENING A B+TREE"
  229. X.LP
  230. XThere are two functions provided for opening a b+tree. The first,
  231. X.B "bt_open()"
  232. Xis intended to look like the
  233. X.B "open(2)"
  234. Xsystem call, and assumes that the caller wishes to open a b+tree with
  235. Xall the default options. These defaults are built into the library,
  236. Xand set the page size to some reasonable value in view of the system buffer
  237. Xsize, cache size to some reasonable value, cache modes to something
  238. Xconservative, and the b+tree data type to string.
  239. X.LP
  240. XThe second function for opening a b+tree,
  241. X.B "bt_optopen()"
  242. Xallows a user to set a larger variety of options. The interface to the
  243. Xfunction is through a variable length argument list, terminated by a
  244. Xzero. Each of the arguments is interpreted in sequence as a request
  245. Xfor a specific parameter in the b+tree to be set.
  246. XEach request may be followed by one
  247. Xor more arguments, depending on the specific request. Omission of an
  248. Xargument, or the terminating zero will result in disaster. Not all of
  249. Xthe request are required, and if the request is omitted, the default
  250. Xwill be taken. Those marked as mandatory must be provided.
  251. X.LP
  252. X.B "Options to bt_optopen()"
  253. X.LP
  254. X.I BT_PATH:
  255. XThis option must be followed by a null-terminated string specifying the
  256. Xpath name of the file to open. \fIThis value must be provided\fR.
  257. X.LP
  258. X.I BT_PSIZE:
  259. XThis option must be followed by an integer value indicating the desired
  260. Xpage size to use. The default is to use a value based on the system
  261. Xbuffer size.
  262. X.LP
  263. X.I BT_CACHE:
  264. XThis option must be followed by an integer value specifying the number
  265. Xof cache buffers to use in addition to
  266. Xthe minimum number of cache buffers required for scratch pages. The
  267. Xdefault is to use a reasonable sized cache, which should be adequate.
  268. X.LP
  269. X.I BT_CFLAG:
  270. XThis option must be followed by a flag value which specifies the manner
  271. Xin which cache buffers are to be handled. The permitted values are
  272. Xdefined as
  273. X.I BT_NOCACHE
  274. X.I BT_ROCACHE
  275. Xor
  276. X.I BT_RWCACHE
  277. Xstanding for (respectively) no cache, read-only cache, and read-write
  278. Xcache. The effects of these values is as follows: When no cache is
  279. Xindicated, pages are read from disk every time a read request is issued,
  280. Xand are written to disk with every write request. The minimal existing
  281. Xcache buffers are still required for splitting and insertion, but data
  282. Xis never taken from them. When read-only cache is in effect, reads may
  283. Xbe returned directly out of cache, but all page write requests are still 
  284. Xflushed immediately to disk. This means that programs which exit suddenly
  285. Xfor some reason or another need be less concerned about whether or not
  286. Xthe b+tree index has been flushed. The read-write cache option allows
  287. Xpages to be written directly into cache, where they are only flushed to
  288. Xdisk when expired, or the tree is closed. This mode should save some
  289. Xtime when building an index in batch mode. At any time, the
  290. X.B "bt_sync()"
  291. Xfunction can be called to flush any modified pages to disk. Closing
  292. Xa b+tree also flushes the cache.
  293. X.LP
  294. X.I BT_OMODE:
  295. XThis option must be followed by an integer value which is used as flags
  296. Xto the 
  297. X.B "open(2)"
  298. Xsystem call.
  299. X.LP
  300. X.I BT_OPERM:
  301. XThis option must be followed by an integer value which is passed to the
  302. X.B "open(2)"
  303. Xsystem call as the permissions information.
  304. X.LP
  305. X.I BT_MAGIC:
  306. XThis option must be followed by a long value which is used as the
  307. Xmagic number for the b+tree. This replaces the default value. One
  308. Xside-effect of setting this value is that the correct value \fImust\fR
  309. Xbe provided again if the tree is re-opened.
  310. X.LP
  311. X.I BT_DTYPE:
  312. XThis option must be followed by a flag value indicating the type of
  313. Xdata that is being stored in the index. The permitted values are
  314. Xdefined as
  315. X.I BT_STRING
  316. X.I BT_INT
  317. X.I BT_LONG
  318. X.I BT_FLOAT
  319. Xand
  320. X.I BT_USRDEF
  321. Xmeaning either string, integer, long, float, or user-defined. The string
  322. Xdata type is the default, and there are functions built into the tree
  323. Xthat improve string performance. Depending on the system architecture,
  324. Xthe compiler, etc, you may have trouble with floats, ints, and longs,
  325. Xas well as user-defined data, due to alignment problems. This can be
  326. Xgotten around only in system-specific ways, so no solution is offered
  327. Xhere.
  328. X.LP
  329. XIf the
  330. X.I BT_USRDEF
  331. Xflag is passed, another value must be passed as well, being a pointer
  332. Xto a function returning an integer - the comparison function. This
  333. Xfunction is expected to be called as:
  334. X.br
  335. X.B "(*cmpf)(key1,length1,key2,length1);"
  336. X.br
  337. Xwhere \fIkey1\fR is the first key, and \fIlength1\fR is its length,
  338. Xand \fIkey2\fR is the second key, with \fIlength2\fR as its length.
  339. XThe function is expected to return zero if the two keys are equal
  340. Xin sort order, a value less than zero if the first key is less than
  341. Xthe second key, and a value greater than zero if the first key is
  342. Xgreater than the second. when using the user-defined data structures,
  343. Xsince the keys may be variable-length, the user is responsible for
  344. Xstructure alignment and other nasties. As long as the keys are a multiple
  345. Xof the system word size, there should be no alignment problems.
  346. X.LP
  347. X.I BT_LABEL:
  348. XThis option must be followed by a character pointer and an integer
  349. Xvalue. The character pointer is used as a label, and is stored in
  350. Xsome spare space at the end of the b+tree file header. The integer
  351. Xvalue must contain the length of the label being provided. If there
  352. Xis insufficient room in the b+tree file header, an error will result.
  353. XThe label can also be read and set using the
  354. X.B "bt_rlabel()"
  355. Xand
  356. X.B "bt_wlabel()"
  357. Xfunctions.
  358. X.SH "BT_OPTOPEN EXAMPLES"
  359. X.nf
  360. X.na
  361. X.ft C
  362. X    BT_INDEX    *p;
  363. X
  364. X    p = bt_optopen(    BT_PATH, "test.dat",
  365. X            BT_MODE, 0600,
  366. X            BT_OMODE, O_CREAT|O_TRUNC,
  367. X            BT_CFLAG, BT_RWCACHE,
  368. X            0);
  369. X.ft R
  370. X.fi
  371. X.ad
  372. X.LP
  373. XThe above would open \fItest.dat\fR with mode 0600, and would create
  374. Xor truncate an existing file. Since the file will be truncated, a new
  375. Xb+tree index will be initialized. The data type of the index will be
  376. Xthe default, as will the cache size. The cache, however, has been
  377. Xflagged to not immediately flush pages to disk on write.
  378. X.br
  379. X.sp
  380. X.nf
  381. X.na
  382. X.ft C
  383. X    BT_INDEX    *p;
  384. X    extern        int    mycompare();
  385. X
  386. X    p = bt_optopen(    BT_PATH, "test2.dat",
  387. X            BT_DTYPE, BT_USRDEF, mycompare,
  388. X            BT_PSIZE, (BUFSIZ * 2),
  389. X            BT_LABEL, "foo", 3,
  390. X            0);
  391. X.ft R
  392. X.fi
  393. X.ad
  394. X.LP
  395. XThe above would open \fItest2.dat\fR with page size of double the system
  396. Xbuffer size. The data type stored is indicated to be user-defined, and
  397. Xa comparison function
  398. X.B "mycompare()"
  399. Xis provided to compare keys. The b+tree index is labeled \fIfoo\fR for
  400. Xmysterious reasons.
  401. X.SH "OTHER B+TREE FUNCTIONS"
  402. X.LP
  403. X.B "int bt_delete(btree,key,len)"
  404. X.br
  405. X.B "BT_INDEX *btree;"
  406. X.br
  407. X.B "bt_chrp key;"
  408. X.br
  409. X.B "int len;"
  410. X.br
  411. XThis function will search for the key and delete it from the index. If the
  412. Xkey is not present in the index, the value
  413. X.B BT_NF
  414. Xis returned. 
  415. X.LP
  416. X.B "int bt_find(btree,key,len,rrn)"
  417. X.br
  418. X.B "BT_INDEX *btree;"
  419. X.br
  420. X.B "bt_chrp key;"
  421. X.br
  422. X.B "int len;"
  423. X.br
  424. X.B "off_t *rrn;"
  425. X.br
  426. XThis function will search for the key and store the data pointer in
  427. X.B rrn,
  428. Xreturning
  429. X.B BT_NF
  430. Xif the key is not present in the index. The current location in the
  431. Xindex is stored to "point" to the located key, or to the key
  432. Xwhere it should have been if it was not present.
  433. X.LP
  434. X.B "int bt_goto(btree,d)"
  435. X.br
  436. X.B "BT_INDEX *btree;"
  437. X.br
  438. X.B "int d; /* BT_EOF or BT_BOF */"
  439. X.br
  440. XThis function will move the current b+tree location to either the
  441. Xhighest key in the tree or the lowest, depending on the value in
  442. X.B d.
  443. XIf the value is
  444. X.B BT_EOF
  445. Xthe locator will be moved to the highest key in the tree, if it is
  446. X.B BT_BOF
  447. Xthe locator moves to the lowest key. The current location in the
  448. Xindex is stored if the call is successful.
  449. X.LP
  450. X.B "int bt_insert(btree,key,len,rrn,dupflg)"
  451. X.br
  452. X.B "BT_INDEX *btree;"
  453. X.br
  454. X.B "bt_chrp key;"
  455. X.br
  456. X.B "int len;"
  457. X.br
  458. X.B "off_t rrn;"
  459. X.br
  460. X.B "int dupflg;"
  461. X.br
  462. XThis function inserts the key in an index, with the data pointer
  463. Xvalue in
  464. X.B rrn.
  465. XDuplicate keys are not supported, and
  466. X.B BT_ERR
  467. Xwill be returned if an attempt is made to insert a duplicate value,
  468. Xunless
  469. X.B dupflg
  470. Xis non-zero, in which case the value in
  471. X.B rrn
  472. Xis used to replace the value currently stored in the index as a 
  473. Xdata pointer. This operation is more efficient than deleting a key
  474. Xand re-inserting it, and should be used where changing the
  475. Xdata pointer is desired. When a new key is inserted in the index,
  476. Xthe current location in the index is invalidated. Thus, inserting a
  477. Xkey and calling
  478. X.B bt_traverse
  479. Xwill cause a seek to the beginning or the end of the index.
  480. X.LP
  481. X.B "int bt_traverse(btree,d,kbuf,maxlen,retlen,retrrn)"
  482. X.br
  483. X.B "BT_INDEX *btree;"
  484. X.br
  485. X.B "int d; /* BT_EOF or BT_BOF */"
  486. X.br
  487. X.B "bt_chrp kbuf;"
  488. X.br
  489. X.B "int maxlen;"
  490. X.br
  491. X.B "int *retlen;"
  492. X.br
  493. X.B "off_t *retrrn;"
  494. X.br
  495. XThis function will move forward or backwards across the keys in the
  496. Xtree, depending on the value in
  497. X.B d.
  498. XIf the value in 
  499. X.B d
  500. Xis
  501. X.B BT_EOF
  502. Xthe traverse will move towards the high end of the index, if it is
  503. X.B BT_BOF
  504. Xthe traverse will move towards the low end. If the traverse is
  505. Xsuccessful, the next (or previous) key is placed in
  506. X.B kbuf,
  507. Xthe data pointer in
  508. X.B retrrn,
  509. Xand the length of the key is stored in
  510. X.B retlen.
  511. X.B maxlen
  512. Xis checked to ensure that there is sufficient room in the user-provided
  513. Xbuffer for the key, to prevent overruns. If an overrun would occur, the
  514. Xfunction returns
  515. X.B BT_ERR
  516. Xand
  517. X.B bt_errno
  518. Xfor the index is set to
  519. X.B BT_BTOOSMALL.
  520. XIf the end of the index is encountered, and the traverse can proceed no
  521. Xfurther, the value
  522. X.B BT_EOF
  523. Xis returned by the function, or
  524. X.B BT_BOF
  525. Xis returned if the beginning of the index is reached. If the current
  526. Xlocation in the index is undefined at the time of the call to
  527. X.B bt_traverse
  528. Xa 
  529. X.B bt_goto
  530. Xis performed to the \fIopposite\fR end of the index from the direction
  531. Xin which the traverse is being performed. In this way, a tree can be
  532. Xopened and dumped by simply performing successive calls to
  533. X.B bt_traverse.
  534. X.LP
  535. X.B "void bt_perror(btree,s)"
  536. X.br
  537. X.B "BT_INDEX *btree;"
  538. X.br
  539. X.B "char *s;"
  540. X.br
  541. XThis function prints out any error messages currently associated with
  542. Xthe index, in the manner of the
  543. X.B "perror(3)"
  544. Xfunction. If there is no current error detected in the index, and a
  545. Xsystem error is present in
  546. X.B errno,
  547. X.B perror
  548. Xis called with the string
  549. X.B s.
  550. X.LP
  551. X.B "int bt_rlabel(btree,buf,siz)"
  552. X.br
  553. X.B "BT_INDEX *btree;"
  554. X.br
  555. X.B "bt_chrp buf;"
  556. X.br
  557. X.B "int siz;"
  558. X.br
  559. XThis function reads the label from the index and places it in
  560. X.B buf,
  561. Xchecking the value of
  562. X.B siz
  563. Xto ensure there is enough room. Note that the software keeps no count of
  564. Xhow many bytes of data are in the label.
  565. X.LP
  566. X.B "int bt_wlabel(btree,buf,siz)"
  567. X.br
  568. X.B "BT_INDEX *btree;"
  569. X.br
  570. X.B "bt_chrp buf;"
  571. X.br
  572. X.B "int siz;"
  573. X.br
  574. XThis function writes the contents of
  575. X.B buf,
  576. Xto the index label, consisting of 
  577. X.B siz
  578. Xbytes.
  579. X.LP
  580. X.B "int bt_sync(btree)"
  581. X.br
  582. X.B "BT_INDEX *btree;"
  583. X.br
  584. XThis function causes any dirty cache buffers in the index buffer cache to
  585. Xbe flushed to disk.
  586. X.LP
  587. X.B "int bt_close(btree)"
  588. X.br
  589. XThis function closes a b+tree index and frees all dynamically allocated
  590. Xmemory.
  591. X.LP
  592. X.B "int bt_load(btree,key,len,rrn,flag)"
  593. X.br
  594. XThis function performs an optimal in-order load of a set of keys. The keys
  595. Xmust be presented in \fBREVERSE\fP sort order. The advantages this function
  596. Xconfers are several, and it should be used any time an index is being
  597. Xbulk-loaded, or is being rebuilt. When an index is built with
  598. X.B bt_load
  599. Xthe pages are filled in descending order, rather than through random
  600. Xaccess search as in
  601. X.B bt_insert.
  602. XAdditionally, each page is filled to capacity, which means that less space
  603. Xis taken up for the index, and less time is required to search the index.
  604. XFor large indices, the benefit of occasionally optimizing the index by
  605. Xrebuilding it with
  606. X.B bt_load
  607. Xcannot be sufficiently emphasized. Storage savings up up to 50% can be
  608. Xrealized, and search efficiency can be improved considerably.
  609. X.LP
  610. XTo use
  611. X.B bt_load,
  612. Xthe function must first be called on an empty index, or one that is
  613. Xdisposable, with the
  614. X.B key,
  615. X.B len,
  616. Xand
  617. X.B rrn
  618. Xvalues equal to zero. The
  619. X.B flag
  620. Xargument must be
  621. X.B BT_BOF
  622. Xindicating that the file is to be initialized.
  623. XThis causes the tree to be re-initialized through a call to
  624. X.B bt_zap.
  625. XOnce the first call the
  626. X.B bt_load
  627. Xhas been made, any number of subsequent calls can be made, with
  628. X.B key,
  629. X.B len,
  630. Xand
  631. X.B rrn
  632. Xvalues to insert in the index. The
  633. X.B flag
  634. Xargument should be set to
  635. X.B BT_OK
  636. Xto indicate that the keys are valid keys.
  637. XAfter all the keys have been inserted, a final call to
  638. X.B bt_load
  639. Xmust be made, with the
  640. X.B key,
  641. X.B len,
  642. Xand
  643. X.B rrn
  644. Xequal to zero again, and the
  645. X.B flag
  646. Xargument equal to
  647. X.B BT_EOF
  648. Xindicating that the end of the load has been reached. At that time,
  649. Xfurther clean-up is performed, and the new b+tree index can be used
  650. Xnormally.
  651. X.LP
  652. XFor purposes of performance in running
  653. X.B bt_load
  654. Xhaving a reasonable sized cache (about 3 spare pages) and the cache
  655. Xflags set to
  656. X.B BT_RWCACHE
  657. Xwill reduce load times. Increasing the cache by more than a
  658. Xmoderate amount will not drastically improve load times, since the
  659. Xindex is not searched during inserts.
  660. X.LP
  661. XDuring any of the calls to
  662. X.B bt_load
  663. Xif an error condition is encountered, the usual
  664. X.B BT_ERR
  665. Xwill be returned. If the error is anything more serious than an
  666. Xoversized key, or zero-length key, the index will be unusable.
  667. X.LP
  668. X.B "int bt_zap(btree)"
  669. X.br
  670. XThis function resets the b+tree index to an empty state, while retaining
  671. Xany set values for page size, etc. Note that this function will only free
  672. Xdisk space that has been allocated on systems that have the
  673. X.B "ftruncate(2)"
  674. Xsystem call. In order to free disk space on systems that do not
  675. Xhave
  676. X.B ftruncate
  677. Xthe index file must be unlinked and re-created.
  678. X.SH "MACROS"
  679. X.LP
  680. XSince these values are all macros, they should be used only with
  681. Xcaution, to avoid side-effects. Mostly these should not be used by
  682. Xuser-level code, but providing a common interface seemed better
  683. Xthan the alternative.
  684. X.LP
  685. X.B "bt_fileno(btree)"
  686. Xpoints to the file descriptor (integer value) of the index. Users should not
  687. Xfiddle with this unless they know what they're about.
  688. X.LP
  689. X.B "bt_pagesiz(btree)"
  690. Xpoints to the size (integer value) of the b+tree index pages.
  691. X.LP
  692. X.B "bt_dtype(btree)"
  693. Xpoints to the data type if the index. It will be one of the values
  694. Xdiscussed in opening a b+tree.
  695. X.LP
  696. X.B "bt_cmpfn(btree)"
  697. Xpoints to the comparison function used by user-defined data type b+trees.
  698. XIt is possible to reset this on the fly, though the results are not under
  699. Xwarranty.
  700. X.LP
  701. X.B "bt_errno(btree)"
  702. Xpoints to the integer error number value. Definitions of the error codes
  703. Xare in
  704. X.B "btree.h".
  705. X.LP
  706. X.B "bt_clearerr(btree)"
  707. Xresets the index error value to indicate there is no error. This is
  708. Xperformed automatically after every successful function call.
  709. X.LP
  710. X.B "BT_MAXK(btree)"
  711. Xyields an integer value that gives the largest possible size that a
  712. Xkey can be, given the page size of the b+tree. This size is actually
  713. Xsmaller than the largest size of a key that can really be fit in a
  714. Xpage, but is calculated to reliably permit even splitting and promotion.
  715. X.LP
  716. X.B "BT_LABSIZ(btree)"
  717. Xyields an integer value that gives the largest possible amount of
  718. Xspace that can be used for an index label.
  719. X.SH "SEE ALSO"
  720. X.SH "INTERNAL FUNCTIONS"
  721. X.LP
  722. XThe following functions are internal functions used by the b+tree library.
  723. XCare should be taken to avoid declaring functions with names that clash:
  724. X.B bt_delpg,
  725. X.B bt_dump,
  726. X.B bt_freepage,
  727. X.B bt_genprx,
  728. X.B bt_inspg,
  729. X.B bt_keyof,
  730. X.B bt_newpage,
  731. X.B bt_requeue,
  732. X.B bt_rpage,
  733. X.B bt_seekdown,
  734. X.B bt_splpg,
  735. X.B bt_srchpg,
  736. X.B bt_wpage,
  737. X.B bt_wsuper
  738. X.LP
  739. XIn general, all the b+tree functions
  740. Xand macros are prefixed with
  741. X.B bt_...
  742. Xand constants with
  743. X.B BT_...
  744. X.SH DIAGNOSTICS
  745. X.LP
  746. XThe value
  747. X.B BT_OK
  748. Xis returned whenever a function is successful.
  749. X.LP
  750. XThe value
  751. X.SM
  752. X.B BT_ERR
  753. Xis returned to indicate some form of failure in any operation performed on 
  754. Xa valid
  755. X.B BT_INDEX.
  756. XAll valid b+tree indices contain their own error number that is set to
  757. Xindicate the cause of a failure, and can be accessed with the macro
  758. X.B "bt_errno(btindex)"
  759. X(where
  760. X.B btindex
  761. Xis a valid b+tree index). A function 
  762. X.B "bt_perror(btindex,string)"
  763. X(where 
  764. X.B string
  765. Xis a character pointer and
  766. X.B btindex
  767. Xis a valid b+tree index) is provided, which prints an appropriate error
  768. Xmessage on the standard error. If the error is not b+tree-related, any
  769. Xexisting system messages apropos existing conditions are printed by
  770. Xcalling
  771. X.B "perror()"
  772. XAdditionally, access to the error strings is available through the
  773. Xexternal array
  774. X.B "bt_errs[]".
  775. XConstant value codes for each error are defined in
  776. X.B btree.h
  777. Xfor symbolic reference.
  778. X.LP
  779. XErrors are cleared after every successful call to a function. They can
  780. Xalso be cleared using the
  781. X.B "bt_clearerr()"
  782. Xmacro.
  783. X.LP
  784. XThe value
  785. X.SM
  786. X.B NULL
  787. Xis returned to indicate that a
  788. X.SM
  789. X.B BT_INDEX
  790. Xpointer has not been initialized properly. Since no valid
  791. X.B BT_INDEX
  792. Xis returned, 
  793. X.B "bt_perror()"
  794. Xcannot be used to determine the nature of an error.
  795. X.LP
  796. XThe values
  797. X.B BT_EOF
  798. Xand
  799. X.B BT_BOF
  800. Xare returned if a call to
  801. X.B "bt_traverse()"
  802. Xreaches the end or beginning of the index.
  803. X.LP
  804. XThe value
  805. X.B BT_NF
  806. Xis returned if a call to
  807. X.B "bt_find()"
  808. Xfails to find the requested key, but encounters no error.
  809. X.SH BUGS
  810. X.LP
  811. XThere may be problems with pointer alignment on some architectures,
  812. Xespecially if arbitrary structure alignment is not supported.
  813. X.LP
  814. XDue to the alignment problem, users defining their own data types must
  815. Xbe careful to keep them of such a size that they align well, depending
  816. Xon architecture. Fixed-size user-defined structures will probably 
  817. Xbenefit by being padded out to some alignment boundary. Variable-size
  818. Xuser-defined structures should perform thier own padding, even if
  819. Xit requires wasting some space.
  820. X.SH LIMITATIONS
  821. X.LP
  822. XEvery effort has been made to eliminate gratuitous limitations. There
  823. Xis no built-in limit to the depth allowed a tree, as an internal stack
  824. Xis maintained dynamically. There is no built-in limit to page sizes,
  825. Xnumbers of keys, etc, except those inherent in the
  826. Xarchitecture. There is no fixed size to the internal cache, though
  827. Xthere is a fixed minimum that will always be allocated for use as
  828. Xscratch buffers for page splitting, etc. When not being used as such,
  829. Xthey are used to cache disk pages. Assume that at least 4 buffers
  830. Xwill always be allocated.
  831. X.SH ALGORITHMS
  832. X.LP
  833. XThe algorithms used are basically the standard b+tree algorithm as
  834. Xdescribed in countless texts. Some shortcuts are made. Since the
  835. Xkeys can be variable length, the order of the tree is, perforce,
  836. Xvariable. Splitting tries to fill roughly 1/2 of each page during
  837. Xa split, but with a deliberate bias towards the lower page in the
  838. Xsplit, since that is the one which may give up a key for promotion
  839. Xif the page is an internal one. Unlike some b+trees that have two
  840. Xdifferent page structures for internal and leaf pages, this library
  841. Xuses the same structure for both, since no data is stored in the
  842. Xleaf. There is minor wastage as a result, but the size of the
  843. Xobject code is kept down.
  844. X.LP
  845. XDeletes are not implemented in accordance
  846. Xwith the b+tree algorithm, in that pages are not combined as they
  847. Xempty, nor are keys redistributed.  A result is that search performance
  848. Xdoes not improve much as a tree empties, though it does not get
  849. Xworse either. Another side-effect is that while pages may empty out,
  850. Xif the index is re-filled, the inserts will be more efficient,
  851. Xsince the likelihood of having to split a page drops. These assumptions
  852. Xhold true as long as the data is roughly randomly distributed across
  853. Xits range.
  854. X.SH AUTHOR
  855. X.LP
  856. XMarcus J. Ranum
  857. END_OF_FILE
  858. if test 24047 -ne `wc -c <'b+tree/doc/btree.3'`; then
  859.     echo shar: \"'b+tree/doc/btree.3'\" unpacked with wrong size!
  860. fi
  861. chmod +x 'b+tree/doc/btree.3'
  862. # end of 'b+tree/doc/btree.3'
  863. fi
  864. if test -f 'b+tree/utils/btest.c' -a "${1}" != "-c" ; then 
  865.   echo shar: Will not clobber existing file \"'b+tree/utils/btest.c'\"
  866. else
  867. echo shar: Extracting \"'b+tree/utils/btest.c'\" \(18333 characters\)
  868. sed "s/^X//" >'b+tree/utils/btest.c' <<'END_OF_FILE'
  869. X#include    <stdio.h>
  870. X#include    <ctype.h>
  871. X#include    <sys/types.h>
  872. X#include    <sys/file.h>
  873. X#include    "btree.h"
  874. X
  875. X/*
  876. X         (C) Copyright, 1988, 1989 Marcus J. Ranum
  877. X                    All rights reserved
  878. X
  879. X
  880. X          This software, its documentation,  and  supporting
  881. X          files  are  copyrighted  material  and may only be
  882. X          distributed in accordance with the terms listed in
  883. X          the COPYRIGHT document.
  884. X*/
  885. X
  886. X
  887. X/*
  888. X    this program does pretty much one of everything to do with the
  889. X    b+tree library. it does the usual deletes, scans, dumps, etc,
  890. X    and shows a few of the tricks that can be done with user defined
  891. X    data types, builtin data types, and so forth. no attempt is
  892. X    made to make the code gorgeous, rather simple and readable.
  893. X
  894. X    in a real application, some of the things done here should NOT
  895. X    be done. the dump structure code and page dump code relies on
  896. X    internal stuff. for real user-level applications, anything
  897. X    that includes btinternal.h is making a BIG mistake and is
  898. X    poking its nose where it should not. users should not make
  899. X    calls to bt_rpage() unless they are doing something that has
  900. X    been carefully thought out. besides, that internal code
  901. X    could change without warning. every attempt will be made to
  902. X    keep the interface to the user-level functions the same,
  903. X    despite any internal mods.
  904. X
  905. X    Enjoy!
  906. X        --mjr();
  907. X*/
  908. X
  909. X/* only included because this uses some internal routines */
  910. X#include    "btconf.h"
  911. X#include    "btintern.h"
  912. X
  913. X#ifndef    lint
  914. Xstatic char *rcsid = "$Header: /atreus/mjr/hacks/btree/utils/RCS/btest.c,v 1.1 89/10/24 10:09:28 mjr Rel $";
  915. X#endif
  916. X
  917. X/*    do not judge the library code by this humble test harness    */
  918. X/*    the globals are simply a convenience, here where it matters not    */
  919. XBT_INDEX    *globf = NULL;    /* global index handle */
  920. X
  921. X#define    MAXARG    40
  922. Xchar    *globargv[MAXARG];        /* args for commands */
  923. Xint    globargc;
  924. Xchar    globname[500];
  925. X
  926. X/* for tweaking, using big pages is boring */
  927. X#define    TESTPSIZ    61
  928. X
  929. Xextern    char    *strcpy();
  930. Xextern    char    *malloc();
  931. Xextern    char    *rindex();
  932. Xextern    long    atol();
  933. Xextern    float    atof();
  934. X
  935. Xvoid do_open(), do_close(), do_quit(), do_wlabel(), printk();
  936. Xvoid do_insert(), do_help(), do_zap(), do_stats(), do_revload();
  937. Xvoid do_find(), do_head(), do_tail(), do_dump(), do_load();
  938. Xvoid do_next(), do_prev(), do_rlabel(), do_delete();
  939. X
  940. Xvoid    enargv();    /* function to parse user args into strings */
  941. Xvoid    doit();        /* dispatch function */
  942. Xcaddr_t    encode();    /* user argument encoder funct. */
  943. X
  944. X/* this is the comparison function needed for the sample user-defined data */
  945. Xint mycompare();
  946. X
  947. X/* and this is the sample data structure */
  948. Xstruct    point    {
  949. X    int    xcoord;
  950. X    int    ycoord;
  951. X};
  952. X
  953. X#ifdef    YES_BT_DEBUG
  954. Xvoid do_pagedump(), do_struct();
  955. X#endif
  956. X
  957. Xstruct    cmd {
  958. X    char    *name;
  959. X    char    *usage;
  960. X    void    (*func)();
  961. X    int    narg;        /* # of args req'd */
  962. X    int    op;        /* needs an open index to call */
  963. X};
  964. X
  965. Xstatic    char    *prompt = "btest->";
  966. X
  967. X/* command dispatch table */
  968. Xstruct    cmd    cmds[] = {
  969. X"close",    "close",            do_close,    1,    1,
  970. X"delete",    "delete key [key2...]",        do_delete,    2,    1,
  971. X"dump",        "dump [-r]",            do_dump,    1,    1,
  972. X"exit",        "exit",                do_quit,    1,    0,
  973. X"find",        "find key",            do_find,    2,    1,
  974. X"head",        "head",                do_head,    1,    1,
  975. X"help",        "help",                do_help,    1,    0,
  976. X"insert",    "insert key [rrn]",        do_insert,    2,    1,
  977. X"label",    "label string",            do_wlabel,    2,    1,
  978. X"load",        "load file (unsorted input)",    do_load,    2,    1,
  979. X"next",        "next [count]",            do_next,    1,    1,
  980. X"open",        "open database [type] [size]",    do_open,    2,    0,
  981. X#ifdef    YES_BT_DEBUG
  982. X"page",        "page page# [page#...]",    do_pagedump,    2,    1,
  983. X#endif
  984. X"plabel",    "plabel (show label)",        do_rlabel,    1,    1,
  985. X"prev",        "prev [count]",            do_prev,    1,    1,
  986. X"quit",        "quit",                do_quit,    1,    0,
  987. X"revload",    "revload file (rev sorted)",    do_revload,    2,    1,
  988. X"stats",    "stats (print internal data)",    do_stats,    1,    1,
  989. X"tail",        "tail",                do_tail,    1,    1,
  990. X#ifdef    YES_BT_DEBUG
  991. X"x",        "x (dump struct)",        do_struct,    1,    1,
  992. X#endif
  993. X"zap",        "zap (toast current index)",    do_zap,        1,    1,
  994. X"?",        "?",                do_help,    1,    0,
  995. X0,        0,                0,        0,    0
  996. X};
  997. X
  998. X
  999. Xmain(ac,av)
  1000. Xint    ac;
  1001. Xchar    **av;
  1002. X{
  1003. X    int    x;
  1004. X    char    buf[BUFSIZ];
  1005. X
  1006. X    /* enargv() makes a string look like an arg. vector. */
  1007. X    /* doit dispatches the stuff, calls functions, etc */
  1008. X    /* functions must have at least the given # of args */
  1009. X    /* last flag in a command if not zero means an index */
  1010. X    /* must be open in order to call that function */
  1011. X    
  1012. X    if(ac > 1) {
  1013. X        char    **gap = globargv;
  1014. X    
  1015. X        globargc = ac - 1;
  1016. X        while(*++av)
  1017. X            *gap++ = *av;
  1018. X        doit();
  1019. X    } else {
  1020. X        (void)printf(prompt);
  1021. X        while(gets(buf)) {
  1022. X            enargv(buf);
  1023. X            if(globargv[0] != NULL)
  1024. X                doit();
  1025. X
  1026. X            for(x = 0; x < globargc; x++)
  1027. X                (void)free(globargv[x]);
  1028. X
  1029. X            (void)printf(prompt);
  1030. X        }
  1031. X        (void)printf("EOF.\n");
  1032. X    }
  1033. X    do_quit();
  1034. X}
  1035. X
  1036. X
  1037. Xvoid
  1038. Xdoit()
  1039. X{
  1040. X    struct    cmd    *c = cmds;
  1041. X
  1042. X    /* main dispatcher */
  1043. X    while(c->name != 0) {
  1044. X        if(strncmp(c->name,globargv[0],strlen(globargv[0])) == 0) {
  1045. X            if(globargc < c->narg) {
  1046. X                (void)printf("usage:\"%s\"\n",c->usage);
  1047. X                return;
  1048. X            } else {
  1049. X                if(c->op != 0 && globf == NULL) {
  1050. X                    (void)printf("no index open.\n");
  1051. X                    return;
  1052. X                }
  1053. X                (*c->func)();
  1054. X                return;
  1055. X            }
  1056. X        }
  1057. X        c++;
  1058. X    }
  1059. X    (void)printf("unknown command: \"%s\"\n",globargv[0]);
  1060. X    return;
  1061. X}
  1062. X
  1063. X
  1064. Xchar *
  1065. Xwordparse(line,word,delim)
  1066. Xchar    *line,    *word;
  1067. Xint    delim;
  1068. X{
  1069. X    int    quot =0;
  1070. X
  1071. X    /* parse a word, or quoted string into a buffer. */
  1072. X    while (*line && (isspace(*line) || *line == delim))
  1073. X        line++;
  1074. X
  1075. X    if(*line == '\n')
  1076. X        line++;
  1077. X
  1078. X    if (!*line) {
  1079. X        *word = '\0';
  1080. X        return(0);
  1081. X    }
  1082. X
  1083. X    while (*line)
  1084. X    {
  1085. X        if(!quot && (*line == '\"' || *line == '\''))
  1086. X            quot = *line++;
  1087. X
  1088. X        if((isspace(*line) || *line == delim) && !quot) {
  1089. X            break;
  1090. X        } else {
  1091. X            if(quot && *line == quot) {
  1092. X                quot = 0;
  1093. X                line++;
  1094. X            } else {
  1095. X                *word++ = *line++;
  1096. X            }
  1097. X        }
  1098. X    }
  1099. X    *word = '\0';
  1100. X    return(line);
  1101. X}
  1102. X
  1103. X
  1104. Xvoid
  1105. Xenargv(buf)
  1106. Xchar    *buf;
  1107. X{
  1108. X    char    *bufptr;
  1109. X    char    pbuf[BUFSIZ];
  1110. X    
  1111. X    globargc =0;
  1112. X    bufptr = buf;
  1113. X
  1114. X    /* this is kinda gross, but the easiest way to handle */
  1115. X    /* quoted strings, since I already had wordparse() written */
  1116. X    while(bufptr = wordparse(bufptr,pbuf,0)) {
  1117. X        globargv[globargc] = malloc((unsigned)(strlen(pbuf) + 1));
  1118. X        (void)strcpy(globargv[globargc++],pbuf);
  1119. X    }
  1120. X    globargv[globargc] = NULL;
  1121. X}
  1122. X
  1123. X
  1124. Xvoid
  1125. Xdo_open()
  1126. X{
  1127. X    int    ps = TESTPSIZ;
  1128. X    int    typ = BT_DFLTDTYPE;
  1129. X
  1130. X    if(globf != NULL) {
  1131. X        (void)printf("try closing %s first, ok ?\n",globname);
  1132. X        return;
  1133. X    }
  1134. X
  1135. X#ifdef    BTOPEN
  1136. X    if(globargc > 2) {
  1137. X        (void)printf("cannot specify data type when using bt_open()\n");
  1138. X        return;
  1139. X    }
  1140. X#else
  1141. X    if(globargc > 2) {
  1142. X        if(!strcmp(globargv[2],"int")) {
  1143. X            typ = BT_INT;
  1144. X        } else if(!strcmp(globargv[2],"float")) {
  1145. X            typ = BT_FLOAT;
  1146. X        } else if(!strcmp(globargv[2],"long")) {
  1147. X            typ = BT_LONG;
  1148. X        } else if(!strcmp(globargv[2],"string")) {
  1149. X            typ = BT_STRING;
  1150. X        } else if(!strcmp(globargv[2],"userdef")) {
  1151. X            typ = BT_USRDEF;
  1152. X        } else {
  1153. X            (void)printf("unknown data type \"%s\" - not opened\n",globargv[2]);
  1154. X            (void)printf("use: float, string, long, int, or userdef\n");
  1155. X            return;
  1156. X        }
  1157. X    }
  1158. X#endif
  1159. X
  1160. X    if(globargc > 3) {
  1161. X        if((ps = atoi(globargv[3])) == 0) {
  1162. X            (void)printf("invalid page size 0\n");
  1163. X            return;
  1164. X        }
  1165. X    }
  1166. X
  1167. X#ifdef    BTOPEN
  1168. X    globf = bt_open(globargv[1],O_CREAT,0600);
  1169. X#else
  1170. X    if(typ != BT_USRDEF) {
  1171. X        /* if user-defined we need to pass compare */
  1172. X        /* func, too - hence this special case code */
  1173. X        globf = bt_optopen(BT_PATH,    globargv[1],
  1174. X                BT_OMODE,    O_CREAT,
  1175. X                BT_DTYPE,    typ,
  1176. X                BT_PSIZE,    ps,
  1177. X        0);
  1178. X    } else {
  1179. X        globf = bt_optopen(BT_PATH,    globargv[1],
  1180. X                BT_OMODE,    O_CREAT,
  1181. X                /* note - pass the comparison function */
  1182. X                BT_DTYPE,    typ,    mycompare,
  1183. X                BT_PSIZE,    ps,
  1184. X        0);
  1185. X    }
  1186. X#endif
  1187. X
  1188. X    if(globf == NULL) {
  1189. X        (void)printf("error opening database ");
  1190. X        perror(globargv[1]);
  1191. X        (void)printf("\n");
  1192. X    } else {
  1193. X        (void)printf("opened %s, type %d, with page size %d\n",globargv[1],bt_dtype(globf),bt_pagesiz(globf));
  1194. X        (void)strcpy(globname,globargv[1]);
  1195. X    }
  1196. X
  1197. X    /* in the case where we are opening a user defined data type */
  1198. X    /* tree, that already exists, the pointer will not be set, */
  1199. X    /* because of the logic above (IE - it wont know its a userdef */
  1200. X    /* until it opens) so we set it using a macro from btree.h */
  1201. X    if(globargc == 2 && bt_dtype(globf) == BT_USRDEF)
  1202. X        bt_cmpfn(globf) = mycompare;
  1203. X}
  1204. X
  1205. X
  1206. Xvoid
  1207. Xdo_close()
  1208. X{
  1209. X    if(globf != NULL) {
  1210. X        if(bt_close(globf) == BT_OK)
  1211. X            (void)printf("closed OK\n");
  1212. X        else
  1213. X            (void)printf("error closing\n");
  1214. X    } else {
  1215. X        (void)printf("nothing open\n");
  1216. X    }
  1217. X    globf = NULL;
  1218. X}
  1219. X
  1220. X
  1221. X#ifdef    YES_BT_DEBUG
  1222. Xvoid
  1223. Xdo_pagedump()
  1224. X{
  1225. X    struct    bt_cache *p;
  1226. X    int    x;
  1227. X    off_t    num;
  1228. X
  1229. X    for(x = 1; x < globargc; x++) {
  1230. X        num = (off_t)atol(globargv[x]);
  1231. X        if(num == 0L) {
  1232. X            (void)printf("cannot read \"%s\" as a page #\n",globargv[x]);
  1233. X        } else {
  1234. X            if((p = bt_rpage(globf,num)) == NULL) {
  1235. X                (void)printf("cannot read page %ld\n",num);
  1236. X                return;
  1237. X            } else {
  1238. X                bt_dump(globf,p);
  1239. X            }
  1240. X        }
  1241. X    }
  1242. X}
  1243. X#endif
  1244. X
  1245. X
  1246. Xvoid
  1247. Xdo_quit()
  1248. X{
  1249. X    if(globf != NULL) {
  1250. X        (void)printf("closing %s\n",globname);
  1251. X        if(bt_close(globf) != BT_OK) {
  1252. X            (void)printf("problems closing %s\n",globname);
  1253. X            exit(1);
  1254. X        }
  1255. X    }
  1256. X    exit(0);
  1257. X}
  1258. X
  1259. X
  1260. Xvoid
  1261. Xdo_insert()
  1262. X{
  1263. X    caddr_t    ptr;
  1264. X    off_t    rrn;
  1265. X    static    off_t    rrnval = 1L;
  1266. X    int    len;
  1267. X
  1268. X    if((globargc > 2 && bt_dtype(globf) != BT_USRDEF))
  1269. X        rrn = atol(globargv[2]);
  1270. X    else
  1271. X        rrn = rrnval++;
  1272. X
  1273. X    ptr = encode(globargv[1],globargv[2],&len);
  1274. X
  1275. X    if(bt_insert(globf,ptr,len,rrn,0)== BT_ERR) {
  1276. X        bt_perror(globf,"error in insert");
  1277. X        return;
  1278. X    }
  1279. X}
  1280. X
  1281. X
  1282. Xvoid
  1283. Xdo_revload()
  1284. X{
  1285. X    caddr_t    ptr;
  1286. X    off_t    rrnval = 1L;
  1287. X    int    len;
  1288. X    FILE    *inp;
  1289. X    char    *p;
  1290. X    char    fuf[BUFSIZ];
  1291. X
  1292. X    if((inp = fopen(globargv[1],"r")) == NULL) {
  1293. X        perror(globargv[1]);
  1294. X        return;
  1295. X    }
  1296. X
  1297. X    /* call #1 to bt_load with flag BT_BOF to tell it to start */
  1298. X    if(bt_load(globf,0,0,0L,BT_BOF)== BT_ERR) {
  1299. X        bt_perror(globf,"cannot initialize btree load");
  1300. X        (void)fclose(inp);
  1301. X        return;
  1302. X    }
  1303. X
  1304. X    while(fgets(fuf,sizeof(fuf),inp) != NULL) {
  1305. X        if((p = rindex(fuf,'\n')) != NULL)
  1306. X            *p = '\0';
  1307. X
  1308. X        /* files of user def stuff must be tab separated */
  1309. X        /* for the purposes of this example. */
  1310. X        if(bt_dtype(globf) == BT_USRDEF) {
  1311. X            if((p = rindex(fuf,'\t')) != NULL) {
  1312. X                *p++ = '\0';
  1313. X            } else {
  1314. X                (void)fprintf(stderr,"user-defined data must be tabbed when reading from a file\n");
  1315. X                continue;
  1316. X            }
  1317. X        }
  1318. X    
  1319. X        ptr = encode(fuf,p,&len);
  1320. X        if(bt_load(globf,ptr,len,rrnval++,BT_OK)== BT_ERR) {
  1321. X            bt_perror(globf,"error in load");
  1322. X            break;
  1323. X        } else
  1324. X            (void)printf(".");
  1325. X
  1326. X    }
  1327. X
  1328. X    /* a final call to bt_load with BT_EOF tells it to stop */
  1329. X    if(bt_load(globf,0,0,0L,BT_EOF) == BT_ERR) {
  1330. X        bt_perror(globf,"cannot shut down load");
  1331. X        (void)fclose(inp);
  1332. X        return;
  1333. X    }
  1334. X
  1335. X    (void)fclose(inp);
  1336. X    (void)printf("\ndone\n");
  1337. X}
  1338. X
  1339. X
  1340. Xvoid
  1341. Xdo_load()
  1342. X{
  1343. X    caddr_t    ptr;
  1344. X    off_t    rrnval = 1L;
  1345. X    int    len;
  1346. X    FILE    *inp;
  1347. X    char    *p;
  1348. X    char    fuf[BUFSIZ];
  1349. X
  1350. X    if((inp = fopen(globargv[1],"r")) == NULL) {
  1351. X        perror(globargv[1]);
  1352. X        return;
  1353. X    }
  1354. X
  1355. X    while(fgets(fuf,sizeof(fuf),inp) != NULL) {
  1356. X        if((p = rindex(fuf,'\n')) != NULL)
  1357. X            *p = '\0';
  1358. X
  1359. X        /* files of user def stuff must be tab separated */
  1360. X        /* for the purposes of this example. */
  1361. X        if(bt_dtype(globf) == BT_USRDEF) {
  1362. X            if((p = rindex(fuf,'\t')) != NULL) {
  1363. X                *p++ = '\0';
  1364. X            } else {
  1365. X                (void)fprintf(stderr,"user-defined data must be tabbed when reading from a file\n");
  1366. X                continue;
  1367. X            }
  1368. X        }
  1369. X    
  1370. X        ptr = encode(fuf,p,&len);
  1371. X        if(bt_insert(globf,ptr,len,rrnval++,1)== BT_ERR) {
  1372. X            bt_perror(globf,"\nerror in insert");
  1373. X            break;
  1374. X        } else
  1375. X            (void)printf(".");
  1376. X    }
  1377. X    (void)fclose(inp);
  1378. X    (void)printf("\ndone\n");
  1379. X}
  1380. X
  1381. X
  1382. Xvoid
  1383. Xdo_help()
  1384. X{
  1385. X    struct    cmd    *c = cmds;
  1386. X    (void)printf("short list of commands::\n------------------------\n");
  1387. X    while(c->name != 0) {
  1388. X        (void)printf("%s\n",c->usage);
  1389. X        c++;
  1390. X    }
  1391. X}
  1392. X
  1393. X
  1394. Xvoid
  1395. Xdo_zap()
  1396. X{
  1397. X    if(bt_zap(globf) == BT_ERR) {
  1398. X        bt_perror(globf,"zap");
  1399. X        return;
  1400. X    }
  1401. X    (void)printf("zapped %s\n",globname);
  1402. X}
  1403. X
  1404. X
  1405. Xvoid
  1406. Xdo_stats()
  1407. X{
  1408. X    (void)printf("superblock:\n");
  1409. X    (void)printf("struct\tbt_super {\n\tlong\tmagic=%ld;\n",globf->sblk.magic);
  1410. X    (void)printf("\tint\tpsiz=%d;\n",bt_pagesiz(globf));
  1411. X    (void)printf("\tint\tdtype=%d;\n",bt_dtype(globf));
  1412. X    (void)printf("\tint\tlevs=%d;\n",globf->sblk.levs);
  1413. X    (void)printf("\toff_t\troot=%ld;\n",globf->sblk.root);
  1414. X    (void)printf("\toff_t\tfree=%ld;\n",globf->sblk.free);
  1415. X    (void)printf("\toff_t\thigh=%ld;\n};\n",globf->sblk.high);
  1416. X
  1417. X    (void)printf("struct\tbt_index {\n\tint\tfd=%d;\n",bt_fileno(globf));
  1418. X    (void)printf("\tchar\tdirt=%d;\n",globf->dirt);
  1419. X    (void)printf("\tint\tcflg=%d;\n",globf->cflg);
  1420. X    (void)printf("\tint\tcky=%d;\n",globf->cky);
  1421. X    (void)printf("\toff_t\tcpag=%ld;\n",globf->cpag);
  1422. X    (void)printf("\tint\tshih=%d;\n};\n",globf->shih);
  1423. X}
  1424. X
  1425. X
  1426. Xvoid
  1427. Xdo_find()
  1428. X{
  1429. X    off_t    rrnval;
  1430. X    caddr_t    ptr;
  1431. X    int    len;
  1432. X
  1433. X    ptr = encode(globargv[1],globargv[2],&len);
  1434. X
  1435. X    switch(bt_find(globf,ptr,len,&rrnval)) {
  1436. X        case BT_OK:
  1437. X            (void)printf("found with pointer val=%ld\n",rrnval);
  1438. X            break;
  1439. X
  1440. X        case BT_NF:
  1441. X            (void)printf("key not found.\n");
  1442. X            break;
  1443. X
  1444. X        case BT_ERR:
  1445. X            bt_perror(globf,"find failed");
  1446. X            break;
  1447. X
  1448. X        default:
  1449. X            (void)printf("this should never happen!\n");
  1450. X    }
  1451. X}
  1452. X
  1453. X
  1454. Xvoid
  1455. Xdo_goto(whence)
  1456. Xint    whence;
  1457. X{
  1458. X    if(bt_goto(globf,whence) == BT_ERR)
  1459. X        bt_perror(globf,"error - cannot seek to EOF/BOF of tree!");
  1460. X
  1461. X
  1462. X}
  1463. X
  1464. X
  1465. Xvoid
  1466. Xdo_tail()
  1467. X{
  1468. X    do_goto(BT_EOF);
  1469. X}
  1470. X
  1471. X
  1472. Xvoid
  1473. Xdo_head()
  1474. X{
  1475. X    do_goto(BT_BOF);
  1476. X}
  1477. X
  1478. X
  1479. Xvoid
  1480. Xdo_traverse(whence)
  1481. Xint    whence;
  1482. X{
  1483. X    char    buf[BUFSIZ];
  1484. X    int    retlen;
  1485. X    off_t    rrv;
  1486. X    int    x;
  1487. X    int    cnt;
  1488. X    int    ret;
  1489. X
  1490. X    /* users should not probably look at this */
  1491. X    if(globf->cpag == BT_NULL)
  1492. X        (void)printf("(no currently defined location in tree)\n");
  1493. X
  1494. X    if(globargc == 1)
  1495. X        cnt = 1;
  1496. X    else
  1497. X        cnt = atoi(globargv[1]);
  1498. X
  1499. X    for(x = 0; x < cnt; x++) {
  1500. X        ret = bt_traverse(globf,whence,buf,BUFSIZ,&retlen,&rrv);
  1501. X        switch(ret) {
  1502. X            case BT_ERR:
  1503. X                bt_perror(globf,"cannot traverse to key!");
  1504. X                return;
  1505. X
  1506. X            case BT_EOF:
  1507. X                (void)printf("EOF.\n");
  1508. X                break;
  1509. X
  1510. X            case BT_BOF:
  1511. X                (void)printf("BOF.\n");
  1512. X                break;
  1513. X
  1514. X            case BT_OK:
  1515. X                printk(buf,retlen,rrv);
  1516. X                break;
  1517. X
  1518. X            default:
  1519. X                (void)printf("this should never happen!\n");
  1520. X        }
  1521. X
  1522. X        if(ret == whence)
  1523. X            return;
  1524. X    }
  1525. X}
  1526. X
  1527. X
  1528. Xvoid
  1529. Xdo_next()
  1530. X{
  1531. X    do_traverse(BT_EOF);
  1532. X}
  1533. X
  1534. X
  1535. Xvoid
  1536. Xdo_prev()
  1537. X{
  1538. X    do_traverse(BT_BOF);
  1539. X}
  1540. X
  1541. X
  1542. Xvoid
  1543. Xdo_dump()
  1544. X{
  1545. X    char    buf[BUFSIZ];
  1546. X    int    ret;
  1547. X    int    retlen;
  1548. X    off_t    junk;
  1549. X    int    d;
  1550. X
  1551. X    if(globargc > 1) {
  1552. X        d = BT_BOF;
  1553. X        if(bt_goto(globf,BT_EOF) == BT_ERR) {
  1554. X            bt_perror(globf,"cannot goto EOF");
  1555. X            return;
  1556. X        }
  1557. X    } else {
  1558. X        d = BT_EOF;
  1559. X        if(bt_goto(globf,BT_BOF) == BT_ERR) {
  1560. X            bt_perror(globf,"cannot goto BOF");
  1561. X            return;
  1562. X        }
  1563. X    }
  1564. X
  1565. X    while((ret = bt_traverse(globf,d,buf,BUFSIZ,&retlen,&junk)) == BT_OK) {
  1566. X        printk(buf,retlen,junk);
  1567. X    }
  1568. X    if(ret == BT_ERR)
  1569. X        bt_perror(globf,"error traversing!");
  1570. X}
  1571. X
  1572. X
  1573. X#ifdef    YES_BT_DEBUG
  1574. Xvoid
  1575. Xdo_struct()
  1576. X{
  1577. X    off_t    rrv;
  1578. X    struct    bt_cache *p;
  1579. X
  1580. X    (void)printf("levels:%d\t\troot:%ld\n",globf->sblk.levs,globf->sblk.root);
  1581. X
  1582. X
  1583. X    rrv = bt_pagesiz(globf);
  1584. X    (void)printf("Index Pages:\n");
  1585. X    while(rrv < globf->sblk.high && ((p = bt_rpage(globf,rrv)) != NULL)) {
  1586. X        if(HIPT(p->p) != BT_NULL && HIPT(p->p) != BT_FREE)
  1587. X            bt_dump(globf,p);
  1588. X        rrv += bt_pagesiz(globf);
  1589. X    }
  1590. X
  1591. X    rrv = bt_pagesiz(globf);
  1592. X    (void)printf("\nLeaf Pages:\n");
  1593. X    while(rrv < globf->sblk.high && ((p = bt_rpage(globf,rrv)) != NULL)) {
  1594. X        if(HIPT(p->p) == BT_NULL)
  1595. X            bt_dump(globf,p);
  1596. X        rrv += bt_pagesiz(globf);
  1597. X    }
  1598. X}
  1599. X#endif
  1600. X
  1601. X
  1602. Xvoid
  1603. Xdo_wlabel()
  1604. X{
  1605. X    /* write label size + 1 to include null terminator - hack */
  1606. X    if(bt_wlabel(globf,globargv[1],strlen(globargv[1]) + 1) == BT_ERR) {
  1607. X        bt_perror(globf,"cannot write label");
  1608. X        return;
  1609. X    }
  1610. X}
  1611. X
  1612. X
  1613. Xvoid
  1614. Xdo_rlabel()
  1615. X{
  1616. X    char    lbuf[BUFSIZ];
  1617. X
  1618. X    /* sample read-back of label */
  1619. X    if(bt_rlabel(globf,lbuf,BUFSIZ) == BT_ERR) {
  1620. X        bt_perror(globf,"cannot read label");
  1621. X        return;
  1622. X    }
  1623. X
  1624. X    (void)printf("tree label is \"%s\"\n",lbuf);
  1625. X}
  1626. X
  1627. X
  1628. Xvoid
  1629. Xdo_delete()
  1630. X{
  1631. X    int    len;
  1632. X    caddr_t    ptr;
  1633. X
  1634. X    ptr = encode(globargv[1],globargv[2],&len);
  1635. X    switch(bt_delete(globf,ptr,len)) {
  1636. X        case BT_OK:
  1637. X            (void)printf("deleted.\n");
  1638. X            break;
  1639. X
  1640. X        case BT_NF:
  1641. X            (void)printf("key not found.\n");
  1642. X            break;
  1643. X
  1644. X        case BT_ERR:
  1645. X            bt_perror(globf,"delete failed");
  1646. X            break;
  1647. X
  1648. X        default:
  1649. X            (void)printf("this should never happen!\n");
  1650. X    }
  1651. X}
  1652. X
  1653. X
  1654. Xcaddr_t
  1655. Xencode(b1,b2,lp)
  1656. Xchar    *b1;
  1657. Xchar    *b2;
  1658. Xint    *lp;
  1659. X{
  1660. X    static    int    iv;
  1661. X    static    float    fv;
  1662. X    static    long    lv;
  1663. X    static    struct    point    p;
  1664. X
  1665. X    /* since this test program uses a bunch of data types, this */
  1666. X    /* function interprets the arguments based on what the user */
  1667. X    /* enters, places them in a buffer of the appropriate type */
  1668. X    /* and returns a pointer to it. this is somewhat gross, but */
  1669. X    /* for the purposes of example should suffice. presumably */
  1670. X    /* "real" applications wont need to do all this kinda stuff */
  1671. X    /* the encoded length is stashed in the provided pointer */
  1672. X
  1673. X    switch(bt_dtype(globf)) {
  1674. X        case    BT_STRING:
  1675. X            /* interpret input as a string. just return it */
  1676. X            *lp = strlen(b1);
  1677. X            return(b1);
  1678. X
  1679. X        case    BT_INT:
  1680. X            iv = atoi(b1);
  1681. X            *lp = (int)sizeof(int);
  1682. X            return((caddr_t)&iv);
  1683. X            break;
  1684. X
  1685. X        case    BT_LONG:
  1686. X            lv = atol(b1);
  1687. X            *lp = (int)sizeof(long);
  1688. X            return((caddr_t)&lv);
  1689. X            break;
  1690. X
  1691. X        case    BT_FLOAT:
  1692. X            fv = atof(b1);
  1693. X            *lp = (int)sizeof(float);
  1694. X            return((caddr_t)&fv);
  1695. X            break;
  1696. X
  1697. X        case    BT_USRDEF:
  1698. X            /* this is somewhat gross, but you get the idea */
  1699. X            if(b1 != NULL)
  1700. X                p.xcoord = atoi(b1);
  1701. X            else
  1702. X                p.xcoord = 0;
  1703. X            if(b2 != NULL)
  1704. X                p.ycoord = atoi(b2);
  1705. X            else
  1706. X                p.ycoord = 0;
  1707. X            *lp = (int)sizeof(p);
  1708. X            return((caddr_t)&p);
  1709. X    }
  1710. X    return(NULL);
  1711. X}
  1712. X
  1713. X
  1714. Xvoid
  1715. Xprintk(buf,rl,rv)
  1716. Xcaddr_t    buf;
  1717. Xint    rl;
  1718. Xoff_t    rv;
  1719. X{
  1720. X    struct    point *p;
  1721. X    char    *cp;
  1722. X
  1723. X    switch(bt_dtype(globf)) {
  1724. X        case    BT_STRING:
  1725. X            buf[rl] = '\0';
  1726. X            cp = buf;
  1727. X            (void)printf("key=\"");
  1728. X            while(*cp != '\0') {
  1729. X                if(isprint(*cp))
  1730. X                    (void)printf("%c",*cp);
  1731. X                else
  1732. X                    (void)printf("(0x%x)",*cp);
  1733. X                cp++;
  1734. X            }
  1735. X            (void)printf("\",len=%d,rrv=%ld",rl,rv);
  1736. X            break;
  1737. X
  1738. X        case    BT_INT:
  1739. X            (void)printf("key=%d,rrv=%ld",*(int *)buf,rv);
  1740. X            break;
  1741. X
  1742. X        case    BT_LONG:
  1743. X            (void)printf("key=%ld,rrv=%ld",*(long *)buf,rv);
  1744. X            break;
  1745. X
  1746. X        case    BT_FLOAT:
  1747. X            (void)printf("key=%f,rrv=%ld",*(float *)buf,rv);
  1748. X            break;
  1749. X
  1750. X        case    BT_USRDEF:
  1751. X            /* here we are pretending it is a struct point* */
  1752. X            p = (struct point *)&buf[0];
  1753. X            (void)printf("point=(%d,%d),rrv=%ld",p->xcoord,p->ycoord,rv);
  1754. X            break;
  1755. X    }
  1756. X    (void)printf("\n");
  1757. X}
  1758. X
  1759. X
  1760. X/* sample comparison function for user defined data type. NOTE - I have */
  1761. X/* kinda played loose here, since s1 and s2 are really caddr_ts not pointers */
  1762. X/* to struct points, but this should work just fine. kinda sloppy, though. */
  1763. Xmycompare(s1,l1,s2,l2)
  1764. Xstruct point     *s1;
  1765. Xint    l1;
  1766. Xstruct point    *s2;
  1767. Xint    l2;
  1768. X{
  1769. X    /* since we are using a struct, the lengths are irrelevant */
  1770. X    if(s1->xcoord == s2->xcoord) {
  1771. X        if(s1->ycoord == s2->ycoord)
  1772. X            return(0);
  1773. X        else
  1774. X            return(s1->ycoord - s2->ycoord);
  1775. X    }
  1776. X    return(s1->xcoord - s2->xcoord);
  1777. X}
  1778. END_OF_FILE
  1779. if test 18333 -ne `wc -c <'b+tree/utils/btest.c'`; then
  1780.     echo shar: \"'b+tree/utils/btest.c'\" unpacked with wrong size!
  1781. fi
  1782. # end of 'b+tree/utils/btest.c'
  1783. fi
  1784. echo shar: End of archive 5 \(of 5\).
  1785. cp /dev/null ark5isdone
  1786. MISSING=""
  1787. for I in 1 2 3 4 5 ; do
  1788.     if test ! -f ark${I}isdone ; then
  1789.     MISSING="${MISSING} ${I}"
  1790.     fi
  1791. done
  1792. if test "${MISSING}" = "" ; then
  1793.     echo You have unpacked all 5 archives.
  1794.     rm -f ark[1-9]isdone
  1795. else
  1796.     echo You still need to unpack the following archives:
  1797.     echo "        " ${MISSING}
  1798. fi
  1799. ##  End of shell archive.
  1800. exit 0
  1801.  
  1802.